package com.travel.ticket.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.travel.common.es.TicketEsModel;
import com.travel.common.to.SkuHasStockVo;
import com.travel.common.to.StockSkuTo;
import com.travel.common.utils.R;
import com.travel.ticket.entity.SkuInfoEntity;
import com.travel.ticket.entity.SpuInfoEntity;
import com.travel.ticket.feign.SearchFeignService;
import com.travel.ticket.feign.StockFeignService;
import com.travel.ticket.service.SkuInfoService;
import com.travel.ticket.service.SpuInfoService;
import com.travel.ticket.service.TicketService;
import com.travel.ticket.vo.AttrVo;
import com.travel.ticket.vo.SkuInfoVo;
import com.travel.ticket.vo.SpuInfoVo;
import com.travel.ticket.vo.TicketVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
@Slf4j
public class TicketServiceImpl implements TicketService {

    @Autowired
    SpuInfoService spuInfoService;

    @Autowired
    SkuInfoService skuInfoService;

    @Autowired
    SearchFeignService searchFeignService;

    @Autowired
    StockFeignService stockFeignService;

    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * 保存spu和所有sku信息
     * @param spuInfoVo
     */
    @Override
    public void saveSpuAndSkus(SpuInfoVo spuInfoVo) {
        //1. 保存spu信息
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        //1.1 属性对拷
        BeanUtils.copyProperties(spuInfoVo,spuInfoEntity);
        spuInfoEntity.setUpdateTime(new Date());
        spuInfoEntity.setAddTime(new Date());
        spuInfoEntity.setSaleCount(0);
        spuInfoEntity.setCollectionNum(0);
        //1.2 保存
        spuInfoService.save(spuInfoEntity);

        Integer spuId = spuInfoEntity.getSpuId();
        String image = spuInfoVo.getImage();

        //2. 保存sku信息
        List<SkuInfoEntity> skuInfoEntityList = new ArrayList<>();
        spuInfoVo.getSkus().stream().forEach(sku->{
            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            //2.1 属性对拷
            BeanUtils.copyProperties(sku,skuInfoEntity);
            //2.2 其它属性赋值
            skuInfoEntity.setSpuId(spuId);
            skuInfoEntity.setSaleCount(0);
            skuInfoEntity.setSkuImage(image);
            skuInfoEntityList.add(skuInfoEntity);
            skuInfoEntity.setStock(sku.getStock());


        });
        //2.3 保存
        skuInfoService.saveBatch(skuInfoEntityList);

        //3. 保存spuId与attrId的关联关系
        spuInfoService.saveSpuRelationAttr(spuInfoEntity.getSpuId(),spuInfoVo.getAttrTos());

        //4. 远程调用travel-stock保存sku库存信息
        for (SkuInfoEntity skuInfoEntity : skuInfoEntityList) {
            StockSkuTo stockSkuTo = new StockSkuTo();
            BeanUtils.copyProperties(skuInfoEntity,stockSkuTo);

            // TODO 设置ware_id

            R r = stockFeignService.saveSkuStock(stockSkuTo);
            if(r.getCode() == 0){
                log.info("远程调用travel-stock保存sku库存信息---成功");
            }
        }

        //5. spu信息保存到es中
        //spuId spuName spuDescription location type synthesis hotScore score price saleCount
        saveEs(spuInfoEntity,skuInfoEntityList);
    }

    /**
     * 查看票务详情
     * @param spuId
     * @return
     */
    @Override
    public TicketVo info(Integer spuId) {
        TicketVo ticketVo = new TicketVo();
        SpuInfoEntity byId = spuInfoService.getById(spuId);
        //1. 属性对拷
        BeanUtils.copyProperties(byId,ticketVo);
        //2. 获取该spu的所有attr属性
        List<AttrVo> attrs = spuInfoService.getRelationAttrs(spuId);
        ticketVo.setAttrs(attrs);
        //3. 获取sku中的最低价格和最高价格
        List<SkuInfoEntity> skus = skuInfoService.getSkuListBySpuId(spuId);

        Optional<BigDecimal> minPrice = skus.stream()
                .map(SkuInfoEntity::getPrice)
                .min(BigDecimal::compareTo);

        Optional<BigDecimal> maxPrice = skus.stream()
                .map(SkuInfoEntity::getPrice)
                .max(BigDecimal::compareTo);

        // 类型不同 先使用orElse方法取出值 setScale设置精度，不保留小数
        ticketVo.setMinPrice(minPrice.orElse(BigDecimal.ZERO).setScale(0, RoundingMode.DOWN));
        ticketVo.setMaxPrice(maxPrice.orElse(BigDecimal.ZERO).setScale(0, RoundingMode.DOWN));

        //4. 从reids中获取最新的收藏数和销量
        String collectionNumKey = "ticket_collectionNum:"+spuId;
        String saleCountKey = "spuSaleCount:"+spuId;
        String s1 = redisTemplate.opsForValue().get(collectionNumKey);
        String s2 = redisTemplate.opsForValue().get(saleCountKey);
        if(s1 != null){
            ticketVo.setCollectionNum(Integer.valueOf(s1));
        }else{
            ticketVo.setCollectionNum(0);
        }
        if(s2 != null){
            ticketVo.setSaleCount(Integer.valueOf(s2));
        }else{
            ticketVo.setSaleCount(0);
        }


        System.out.println(ticketVo.toString());
        return ticketVo;
    }


    /**
     * 保存票务信息到es中
     * @param spuInfoEntity
     */
    private void saveEs(SpuInfoEntity spuInfoEntity,List<SkuInfoEntity> skuInfoEntityList) {
        TicketEsModel model = new TicketEsModel();
        //属性对拷
        BeanUtils.copyProperties(spuInfoEntity,model);

        //TODO 综合分数 = 评分分数×0.6 + 热度分数×0.4 后续使用异步任务定时计算更新排序字段
        model.setSynthesis(0.0);

        //TODO 热度分数
        model.setHotScore(0.0);

        //TODO 评分分数
        model.setScore(0.0);

        //销量（对应所有sku的销量和）
        model.setSaleCount(0);

        //价格（对应所有sku中价格最低的）
        BigDecimal price = skuInfoEntityList.stream()
                .map(SkuInfoEntity::getPrice)
                .min(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);
        model.setPrice(price);

        R r = searchFeignService.ticketSave(model);
        if(r.getCode() == 0){
            //远程调用成功
            log.info("票务信息保存es成功。。。");
        }else{
            //远程调用失败
            //TODO 重复调用，接口幂等性
        }
    }
}
